package liming.ai.code.java_maven.tool;

import liming.tool.runnable.HandRunnable;
import org.json.JSONArray;
import org.json.JSONObject;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Collection;

public interface ToJsonInterface {
    default JSONObject toJson() {
        String name;
        if (this.getClass().isAnnotationPresent(JsonField.class)) {
            JsonField annotation = getClass().getAnnotation(JsonField.class);
            if (!annotation.value().isEmpty()) {
                name = annotation.value();
            } else {
                name = this.getClass().getSimpleName();
            }
        } else name = this.getClass().getSimpleName();
        return new JSONObject().put(name, toJsonBody(getClass()));
    }

    default JSONObject toJsonBody(Class<?> clazz) {
        JSONObject jsonObject = new JSONObject();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(JsonField.class))
                handleField(jsonObject, field, this);
        }
        if(clazz.isAnnotationPresent(JsonTime.class))
            addTime(jsonObject);
        return jsonObject;
    }

    static void handleField(JSONObject jsonBody,Field field, Object obj) {
        String name;
        JsonField annotation = field.getAnnotation(JsonField.class);
        if (!annotation.value().isEmpty()) {
            name = annotation.value();
        } else {
            name = field.getName();
        }
        Object value = HandRunnable.run(() -> {
            try {
                if (!field.isAccessible())
                    field.setAccessible(true);
                return field.get(obj);
            } finally {
                field.setAccessible(false);
            }
        });
        if(value instanceof Collection){
            jsonBody.put(name, handleCollection((Collection<?>) value));
        }else if (value instanceof ToJsonInterface) {
            Class<?> type;
            if(field.isAnnotationPresent(JsonType.class)&&field.getAnnotation(JsonType.class).value()!=null){
                type = field.getAnnotation(JsonType.class).value();
            }else type = field.getType();
            JSONObject body = ((ToJsonInterface) value).toJsonBody(type);
            jsonBody.put(name, body);
            if(field.getType().isAnnotationPresent(JsonTime.class)||field.isAnnotationPresent(JsonTime.class)){
                addTime(body);
            }
        }else {
            jsonBody.put(name, value);
        }

    }

    static JSONArray handleCollection(Collection<?> collection) {
        JSONArray jsonArray = new JSONArray();
        for (Object o : collection) {
            if (o instanceof ToJsonInterface)
                jsonArray.put(((ToJsonInterface) o).toJsonBody(o.getClass()));
            else if (o instanceof Collection)
                jsonArray.put(handleCollection((Collection<?>) o));
            else
                jsonArray.put(o);
        }
        return jsonArray;
    }
    static void addTime(JSONObject jsonObject){
        jsonObject.put("$time", System.currentTimeMillis());
    }

    @Target({ElementType.FIELD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface JsonField {
        String value() default "";
    }

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface JsonType {
        Class<?> value();
    }

    /**
     * 在json中
     */
    @Target({ElementType.FIELD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface JsonTime{}
}
